package com.lsj.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lsj.config.redis.RedisKey;
import com.lsj.core.exception.CustomerException;
import com.lsj.core.lock.DistributedLock;
import com.lsj.core.lock.LockKey;
import com.lsj.core.page.QueryPage;
import com.lsj.core.page.ResultPage;
import com.lsj.core.response.ResponseType;
import com.lsj.core.util.ExceptionHelperUtil;
import com.lsj.core.util.QueryHelperUtil;
import com.lsj.dto.sys.RoleDto;
import com.lsj.mapper.SysRoleMapper;
import com.lsj.mapper.SysRoleMenuMapper;
import com.lsj.mapper.SysUserRoleMapper;
import com.lsj.mapper.entity.SysRole;
import com.lsj.mapper.entity.SysRoleMenu;
import com.lsj.mapper.entity.SysUserRole;
import com.lsj.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @Author:lin.sj
 * @Data:2021/7/8 19:56
 * @Desc:
 */
@Service
@CacheConfig(cacheNames = RedisKey.USER_KEY)
public class RoleServiceImpl implements RoleService {
    
    @Autowired
    SysRoleMapper sysRoleMapper;
    @Autowired
    SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    SysRoleMenuMapper sysRoleMenuMapper;

    /**
     * @Author: lin.sj
     * @Date: 2021/8/18 20:20
     * @Desc: 角色新增
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    @DistributedLock(value = LockKey.role_key)
    public RoleDto addRole(RoleDto dto) {
        //检查是否有相同中文名称角色或角色代码
        LambdaQueryWrapper<SysRole> w = QueryHelperUtil.getLambdaWrapper(SysRole.class);
        w.eq(SysRole::getRoleName,dto.getRoleName()).or().eq(SysRole::getRoleCode,dto.getRoleCode());
        Integer repeatCount = sysRoleMapper.selectCount(w);
        if(repeatCount > 0){
            throw new CustomerException(ResponseType.error,"存在相同中文名称角色或相同角色代码的角色，无法新增！");
        }
        Integer sortCount = sysRoleMapper.selectCount(null)+1;
        SysRole sysRole = Convert.convert(SysRole.class, dto);
        //设置角色顺序及角色可用
        sysRole.setSort(sortCount).setStatus(true);
        sysRoleMapper.insert(sysRole);
        return Convert.convert(RoleDto.class,sysRole);
    }

    /**
     * @Author: lin.sj
     * @Date: 2021/8/18 20:20
     * @Desc: 角色删除
     * 删除角色时，要把所有缓存在redis的用户信息都清除掉
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(allEntries = true)
    @DistributedLock(value = LockKey.role_key)
    public void deleteRole(Long roleId) {
        //删除与用户的关联
        LambdaQueryWrapper<SysUserRole> userRoleWhere = QueryHelperUtil.getLambdaWrapper(SysUserRole.class);
        userRoleWhere.eq(SysUserRole::getRoleId,roleId);
        sysUserRoleMapper.delete(userRoleWhere);
        //删除与角色的关联
        LambdaQueryWrapper<SysRoleMenu> roleMenuWhere = QueryHelperUtil.getLambdaWrapper(SysRoleMenu.class);
        roleMenuWhere.eq(SysRoleMenu::getRoleId,roleId);
        sysRoleMenuMapper.delete(roleMenuWhere);
        SysRole sysRole = sysRoleMapper.selectById(roleId);
        updateRoleSort(sysRole.getSort(),9999);
        sysRoleMapper.deleteById(roleId);
    }

    /**
     * @Author: lin.sj
     * @Date: 2021/8/18 20:20
     * @Desc: 更新角色
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    @DistributedLock(value = LockKey.role_key)
    public void updateRole(RoleDto dto) {
        //检查数据是否存在
        SysRole sysRole = sysRoleMapper.selectById(dto.getId());
        ExceptionHelperUtil.nullObjException(sysRole,"当前角色不存在，无法更新！");

        //若当前角色状态不可用时，需要删除user_role表的关联关系
        if(!dto.getStatus()){
            LambdaQueryWrapper<SysUserRole> userRoleWhere = QueryHelperUtil.getLambdaWrapper(SysUserRole.class);
            userRoleWhere.eq(SysUserRole::getRoleId,dto.getId());
            sysUserRoleMapper.delete(userRoleWhere);
        }

        //复制更新的数据到实体并保存，其中角色代码不能改
        BeanUtil.copyProperties(dto,sysRole,"roleCode");
        int updateCount = sysRoleMapper.updateById(sysRole);
        if(updateCount <=0){
            throw new CustomerException(ResponseType.error,"更新失败，请重新尝试！");
        }
        updateRoleSort(sysRole.getSort(),9999);
    }
    /**
     * @Author: lin.sj
     * @Date: 2021/8/18 20:20
     * @Desc: 获取角色信息
     **/
    @Override
    public RoleDto getRoleById(Long roleId) {
        SysRole sysRole = sysRoleMapper.selectById(roleId);
        ExceptionHelperUtil.nullObjException(sysRole,"当前角色不存在！");
        return  Convert.convert(RoleDto.class,sysRole);
    }

    /**
     * @Author: lin.sj
     * @Date: 2021/8/18 20:21
     * @Desc: 获取角色列表
     **/
    @Override
    public ResultPage<RoleDto> listRole(QueryPage<RoleDto> queryPage) {
        QueryWrapper<SysRole> w = QueryHelperUtil.getSimpleWhere(SysRole.class, queryPage.getData());
        Page page = sysRoleMapper.selectPage(queryPage.getMpPage(), w);
        return ResultPage.getResult(page, RoleDto.class);
    }
    /**
     * @Author: lin.sj
     * @Date: 2021/8/18 20:21
     * @Desc: 获取所有的角色列表
     **/
    @Override
    public List<RoleDto> listAllRole() {
        List<SysRole> sysRoles = sysRoleMapper.selectList(null);
        return Convert.toList(RoleDto.class,sysRoles);
    }

    /**
     * @Author: lin.sj
     * @Date: 2021/8/18 20:21
     * @Desc: 更新角色的排序（公用方法）
     **/
    private void updateRoleSort(Integer oldValue,Integer newValue){
        LambdaUpdateWrapper w = new LambdaUpdateWrapper();
        if(newValue.intValue() == oldValue.intValue()){
            return;
        }else if(newValue.intValue() > oldValue.intValue()){
            w.setSql("sort = sort-1 where sort>"+oldValue+" and sort<="+newValue);
        }else if(newValue.intValue() < oldValue.intValue()){
            w.setSql("sort = sort+1 where sort>="+newValue+" and sort<"+oldValue);
        }
        sysRoleMapper.update(null,w);
    }
}
